﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SC2BuildOrderQuickie
{
    public class SecondBucket {
        
        public readonly int Bucket;
        public int Frequency;
        public SecondBucket( int bucket ) { Bucket = bucket; Builds = new List< BOCode >();}
        public List< BOCode > Builds { get; set; }
        
    }

    public class FrequencyCounter{
        SortedDictionary<int, SecondBucket> m_FrequencyCount = new SortedDictionary<int, SecondBucket>();
        private readonly BuildOrderPartition m_Partition;
        public FrequencyCounter( int target_chunk, BuildOrderPartition partition, int bucket_seconds_size ) {
            m_Partition = partition;
            foreach( var bo in partition.Builds ) {
                int second_bucket = bo.SecondBuckets[target_chunk]/bucket_seconds_size;
                SecondBucket bucket;
                if( m_FrequencyCount.TryGetValue( second_bucket, out bucket ) == false ) {
                    bucket = new SecondBucket( second_bucket );
                    m_FrequencyCount.Add( second_bucket, bucket );
                }
                bucket.Builds.Add( bo );
                bucket.Builds.Sort(delegate( BOCode dna, BOCode order_dna ) {
                                       return dna.SecondBuckets[ target_chunk ].CompareTo(
                                           order_dna.SecondBuckets[ target_chunk ] );
                                   });
                bucket.Frequency++;
            }
        }

        public SecondBucket Get(int index ) {
            if (index < 0 || index >= m_FrequencyCount.Count) return m_FrequencyCount.ElementAt( 0 ).Value;
            return m_FrequencyCount.ElementAt(index).Value;
        }
        private int m_SecondsPerBucket;
        public int SecondsPerBucket { get { return m_SecondsPerBucket; } }

        public int Count{ get { return m_FrequencyCount.Count; }}
        public IEnumerable<SecondBucket> Buckets { get {
            foreach (KeyValuePair<int, SecondBucket> pair in m_FrequencyCount) yield return pair.Value;
        } }

        public BuildOrderPartition Partition { get { return m_Partition; } }
    }

    public class QuickChart {
        private FrequencyCounter m_Counter;
        private int m_SelectedSecondBucket;
        private readonly Panel m_Panel;
        private int last_selected_bucket = -1;
        private int m_Chunk;
        public QuickChart( int chunk, Panel panel ) {
            m_Chunk = chunk;
            m_Panel = panel;
            m_Panel.Paint += PanelOnPaint;
            m_Panel.RegionChanged += delegate( object sender, EventArgs args ) { m_Panel.Invalidate(); };
            m_Panel.MouseMove += HandleMouseMove;
        }

        private void HandleMouseMove( object sender, MouseEventArgs mouse_event_args ) {
            if (m_Counter == null) return;
            int x_pixels_per_bucket = m_Panel.Width/m_Counter.Count;
            int bucket_index = mouse_event_args.X/x_pixels_per_bucket;
            if (bucket_index != last_selected_bucket) {
                last_selected_bucket = bucket_index;
                RolloverBucket( m_Counter.Get( bucket_index ).Builds[ 0 ] );
            }
        }
        public event Action<BOCode> RolloverBucket = delegate( BOCode dna ) {  };
        public FrequencyCounter Counter {
            get { return m_Counter; }
            set { 
                m_Counter = value;
                //SelectedSecondBucket = -1;
                m_Panel.Invalidate();

            }
        }

        public int SelectedSecondBucket {
            get {
                return m_SelectedSecondBucket;
            } 
            set {
                m_SelectedSecondBucket = value;
                m_Panel.Invalidate();
            }
        }
        
        private void PanelOnPaint(object sender, PaintEventArgs e ) {
            if (m_Counter == null) return;
            int bottom_box_height = 15;
            int sec_label_box_height = 12;
            int height = m_Panel.Height - bottom_box_height - sec_label_box_height;
            int total_frequency = 0;

            List<SecondBucket> buckets = new List< SecondBucket >(m_Counter.Buckets);
            int x_buckets = buckets.Count;
            int x_pixels_per_bucket = m_Panel.Width/x_buckets;
            int max_y = 0;
            for (int i = 0; i < buckets.Count; i++ ) {
                if (buckets[i].Frequency > max_y) max_y = buckets[ i ].Frequency;
                total_frequency += buckets[ i ].Frequency;
            }
            int y_pixels_per_frequency = (m_Panel.Height / max_y);
            if (y_pixels_per_frequency < 2) y_pixels_per_frequency = 1;
            else if (y_pixels_per_frequency > 10) y_pixels_per_frequency = 10;
            for (int i = 0; i < m_Panel.Height; i+=y_pixels_per_frequency*5 ) {
                e.Graphics.DrawLine(Pens.LightGray, 0, height - i, m_Panel.Width, height - i);
            }

            for (int i = 0; i < buckets.Count; i++)
            {
                e.Graphics.FillRectangle(Brushes.Blue,
                    x_pixels_per_bucket * (i) + 1,
                    height - (y_pixels_per_frequency * buckets[i].Frequency),
                    x_pixels_per_bucket - 1,
                    (y_pixels_per_frequency * buckets[i].Frequency)
                    );

                e.Graphics.DrawString( ( buckets[i].Bucket* 5) + "s",
                    new Font(  m_Panel.Font.FontFamily, 7 ),
                    Brushes.Black,
                    (float)x_pixels_per_bucket * (i) + 2,
                    (float) height 
                    );
                if (m_SelectedSecondBucket == buckets[i].Bucket)
                {
                    using (SolidBrush selected_brush = new SolidBrush(Color.FromArgb(75, Color.Black)))
                    {
                        e.Graphics.FillRectangle(
                            selected_brush,
                            x_pixels_per_bucket * (i),
                            0,
                            x_pixels_per_bucket,
                            height
                            );
                    }
                }
            }

            Rectangle bounding_box = new Rectangle(
                 0, m_Panel.Height - bottom_box_height, m_Panel.Width, bottom_box_height
                );
            Brush box_brush;
            String standard;
            switch((int) total_frequency / (4* (5-m_Chunk) ) ){
                case( 0 ):
                    standard = "UNIQUE";
                    box_brush = new LinearGradientBrush(bounding_box, Color.Orange, Color.Lime, LinearGradientMode.Horizontal);
                    break;
                case (1):
                case (2):
                    standard = "UNCOMMON";
                    box_brush = new LinearGradientBrush(bounding_box, Color.Yellow, Color.Lime, LinearGradientMode.Horizontal);
                    break;
                default:
                    standard = "STANDARD";
                    box_brush = Brushes.Lime;
                    break;
            }

            String format = "{0}:{1}  <-  {2}";
            e.Graphics.FillRectangle(box_brush, bounding_box);
            e.Graphics.DrawString(
                String.Format( format, standard, total_frequency, m_Counter.Partition.Key ), 
                new Font( m_Panel.Font, FontStyle.Bold ), 
                Brushes.Black, 10, m_Panel.Height - bottom_box_height);
        }
    }
}
